﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace AutoDb {
	/// <summary>
	/// 
	/// </summary>
	sealed class LogContext {
		private IDictionary<string, ILogWriter> m_writers;

		private int m_indent;

		/// <summary>
		/// 
		/// </summary>
		public LogContext() {
			m_writers = new Dictionary<string, ILogWriter>(StringComparer.OrdinalIgnoreCase);
			m_indent = 0;
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="name"></param>
		/// <param name="writer"></param>
		public void AddWriter(string name, ILogWriter writer) {
			m_writers.Add(name, writer);
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="name"></param>
		public void RemoveWriter(string name) {
			m_writers.Remove(name);
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="level"></param>
		/// <param name="s"></param>
		private void Write(LogLevel level, string s) {
			foreach (var writer in m_writers) {
				if (level < writer.Value.Level) {
					continue;
				}

				writer.Value.Write(level, s);
			}
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="level"></param>
		/// <param name="s"></param>
		private void WriteLine(LogLevel level, string s) {
			foreach (var writer in m_writers) {
				if (level < writer.Value.Level) {
					continue;
				}

				writer.Value.Write(level, s);
				writer.Value.WriteLine(level);
			}
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="s"></param>
		public void Error(string s) {
			ResetIndent();
			WriteLine(LogLevel.Error, s);
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="fmt"></param>
		/// <param name="args"></param>
		public void Error(string fmt, params object[] args) {
			ResetIndent();
			WriteLine(LogLevel.Error, string.Format(fmt, args));
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="s"></param>
		public void Good(string s) {
			ResetIndent();
			WriteLine(LogLevel.Good, s);
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="fmt"></param>
		/// <param name="args"></param>
		public void Good(string fmt, params object[] args) {
			ResetIndent();
			WriteLine(LogLevel.Good, string.Format(fmt, args));
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="s"></param>
		public void Warn(string s) {
			WriteLine(LogLevel.Warn, s);
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="fmt"></param>
		/// <param name="args"></param>
		public void Warn(string fmt, params object[] args) {
			WriteLine(LogLevel.Warn, string.Format(fmt, args));
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="s"></param>
		public void Title(string s) {
			ResetIndent();
			WriteLine(LogLevel.Title, s);
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="fmt"></param>
		/// <param name="args"></param>
		public void Title(string fmt, params object[] args) {
			ResetIndent();
			WriteLine(LogLevel.Title, string.Format(fmt, args));
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="s"></param>
		public void Info(string s) {
			WriteIndentChars(LogLevel.Info);
			WriteLine(LogLevel.Info, s);
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="fmt"></param>
		/// <param name="args"></param>
		public void Info(string fmt, params object[] args) {
			WriteIndentChars(LogLevel.Info);
			WriteLine(LogLevel.Info, string.Format(fmt, args));
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="s"></param>
		public void Verbose(string s) {
			WriteIndentChars(LogLevel.Verbose);
			WriteLine(LogLevel.Verbose, s);
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="fmt"></param>
		/// <param name="args"></param>
		public void Verbose(string fmt, params object[] args) {
			WriteIndentChars(LogLevel.Verbose);
			WriteLine(LogLevel.Verbose, string.Format(fmt, args));
		}

		/// <summary>
		/// 
		/// </summary>
		private void ResetIndent() {
			m_indent = 0;
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="level"></param>
		private void WriteIndentChars(LogLevel level) {
			if (m_indent > 0) {
				for (int i = 0; i < m_indent; ++i) {
					Write(level, "  ");
				}
			}
		}

		/// <summary>
		/// 
		/// </summary>
		public void Indent() {
			++m_indent;
		}

		/// <summary>
		/// 
		/// </summary>
		public void Unindent() {
			--m_indent;

			if (m_indent < 0) {
				m_indent = 0;
			}
		}

		/// <summary>
		/// 
		/// </summary>
		public void Close() {
			foreach (var writer in m_writers) {
				writer.Value.Close();
			}
		}
	} // end of LogContext.
}
